/**
 * 华容道求解
 */

export default class KlotskiSolve {
    private mLine: number = 0;
    private mRow: number = 0;

    private mCallBack: Function = null;

    /**
    * 1   2   3  
    * 4   5   6
    * 7   8
    * 所有矩阵字典 查重
    */
    private mMapMatrixS: any = null;

    /**
     * 记录每个梯度可能的结果
     * 
     */
    private mMapData: Array<any> = null;


    constructor(call: Function) {
        this.mCallBack = call;
    }
    /**
     * 初始化
     * @param line 
     * @param row 
     */
    public init(line: number, row: number, data: Array<number>): void {
        this.mMapData = [];
        this.mLine = line;
        this.mRow = row;
        this.mMapMatrixS = {};

        let steps: Array<any> = [];
        let step: any = {};
        step["matrix"] = data;
        step["answer"] = [];
        steps.push(step);
        this.mMapData.push(steps);
        this.mMapMatrixS[JSON.stringify(data)] = "1";
    }
    /**
     * 求解
     */
    public solve(): Promise<Array<any>> {
        return new Promise((resolve, reject) => {
            //循环遍历求解
            while (true) {
                let steps: Array<any> = [];
                let lastGrad: Array<any> = this.mMapData[this.mMapData.length - 1];
                console.log(lastGrad.length);
                //遍历作最后一个梯度中所有的结果，求解下一步
                for (let i = 0; i < lastGrad.length; i++) {
                    let matrix = lastGrad[i]["matrix"];
                    let answer = lastGrad[i]["answer"];
                    let result: Array<any> = this.move(matrix, answer, steps);
                    if (result) {
                        console.log("结果：", result);
                        resolve(result);
                        return;
                    }
                }
                
                if(steps.length<=0){
                    console.log("查询结果失败，");
                    resolve(null);
                    return;
                }
                this.mMapData.push(steps);
            }
        });
    }
    private move(matrix: Array<number>, answer: Array<any>, steps: Array<any>): Array<any> {
        for (let i = 0; i < matrix.length; i++) {
            if (matrix[i] != -1) {  //不是空位，检测是否可移动，获取可移动结果
                let result0: Array<any> = this.moveUp(i, matrix, answer, steps);
                let result1: Array<any> = this.moveDown(i, matrix, answer, steps);
                let result2: Array<any> = this.moveLeft(i, matrix, answer, steps);
                let result3: Array<any> = this.moveRight(i, matrix, answer, steps);

                if (result1) {
                    return result1;
                }
                if (result2) {
                    return result2;
                }
                if (result0) {
                    return result0;
                }
                if (result3) {
                    return result3;
                }
            }
        }
        return null;
    }
    /**
     * 当前底i个 向上移动
     * @param i 
     * @param matrix 
     * @param answer 
     * @param steps 
     */
    private moveUp(i: number, matrix: Array<number>, answer: Array<any>, steps: Array<any>): Array<any> {
        let line: number = i % this.mLine;
        let row: number = Math.floor(i / this.mLine);
        if (row - 1 < 0) return null;  //超出边界
        let targetIndex: number = (row - 1) * this.mLine + line;
        if ( matrix[targetIndex] != -1) return null;  //不可移动
        //移动
        //复制新的数组进行修改
        let newMatrix: Array<number> = JSON.parse(JSON.stringify(matrix));
        let newAnswer: Array<any> = JSON.parse(JSON.stringify(answer));
        //互换位置
        let temp: number = newMatrix[i];
        newMatrix[i] = newMatrix[targetIndex];
        newMatrix[targetIndex] = temp;
        newAnswer.push({ "index": i, "dic": 0 });

        if (this.checkIsExist(newMatrix)) {
            return null;
        }

        if (this.checkPass(newMatrix)) {
            return newAnswer;
        }
        let step: any = {};
        step["matrix"] = newMatrix;
        step["answer"] = newAnswer;
        steps.push(step);
    }
    private moveDown(i: number, matrix: Array<number>, answer: Array<any>, steps: Array<any>): Array<any> {
        let line: number = i % this.mLine;
        let row: number = Math.floor(i / this.mLine);
        if (row + 1 >= this.mRow) return null;  //超出边界
        let targetIndex: number = (row + 1) * this.mLine + line;
        if ( matrix[targetIndex] != -1) return null;  //不可移动
        //复制新的数组进行修改
        let newMatrix: Array<number> = JSON.parse(JSON.stringify(matrix));
        let newAnswer: Array<any> = JSON.parse(JSON.stringify(answer));
        //互换位置
        let temp: number = newMatrix[i];
        newMatrix[i] = newMatrix[targetIndex];
        newMatrix[targetIndex] = temp;
        newAnswer.push({ "index": i, "dic": 1 });

        if (this.checkIsExist(newMatrix)) {
            return null;
        }

        if (this.checkPass(newMatrix)) {
            return newAnswer;
        }
        let step: any = {};
        step["matrix"] = newMatrix;
        step["answer"] = newAnswer;
        steps.push(step);
    }
    private moveLeft(i: number, matrix: Array<number>, answer: Array<any>, steps: Array<any>): Array<any> {
        let line: number = i % this.mLine;
        let row: number = Math.floor(i / this.mLine);
        if (line - 1 < 0) return null;  //超出边界
        let targetIndex: number = row * this.mLine + (line - 1);
        if ( matrix[targetIndex] != -1) return null;  //不可移动
        //移动
        //复制新的数组进行修改
        let newMatrix: Array<number> = JSON.parse(JSON.stringify(matrix));
        let newAnswer: Array<any> = JSON.parse(JSON.stringify(answer));
        //互换位置
        let temp: number = newMatrix[i];
        newMatrix[i] = newMatrix[targetIndex];
        newMatrix[targetIndex] = temp;
        newAnswer.push({ "index": i, "dic": 2 });

        if (this.checkIsExist(newMatrix)) {
            return null;
        }

        if (this.checkPass(newMatrix)) {
            return newAnswer;
        }
        let step: any = {};
        step["matrix"] = newMatrix;
        step["answer"] = newAnswer;
        steps.push(step);
    }
    private moveRight(i: number, matrix: Array<number>, answer: Array<any>, steps: Array<any>): Array<any> {
        let line: number = i % this.mLine;
        let row: number = Math.floor(i / this.mLine);
        if (line + 1 >= this.mLine) return null;  //超出边界
        let targetIndex: number = row * this.mLine + (line + 1);
        if ( matrix[targetIndex] != -1) return null;  //不可移动
        //移动
        //移动
        //复制新的数组进行修改
        let newMatrix: Array<number> = JSON.parse(JSON.stringify(matrix));
        let newAnswer: Array<any> = JSON.parse(JSON.stringify(answer));
        //互换位置
        let temp: number = newMatrix[i];
        newMatrix[i] = newMatrix[targetIndex];
        newMatrix[targetIndex] = temp;
        newAnswer.push({ "index": i, "dic": 3 });

        if (this.checkIsExist(newMatrix)) {
            return null;
        }

        if (this.checkPass(newMatrix)) {
            return newAnswer;
        }
        let step: any = {};
        step["matrix"] = newMatrix;
        step["answer"] = newAnswer;
        steps.push(step);
    }
    /**
     * 检测是否通关
     */
    private checkPass(matrix: Array<number>): boolean {
        if (matrix[this.mRow * this.mLine - 1] != -1) return false;
        for (let i = 0; i < this.mRow * this.mLine - 1; i++) {
            if (matrix[i] != i + 1) {
                return false;
            }
        }
        console.log(matrix)
        return true;
    }
    /**
     * 检测是否重复
     */
    private checkIsExist(matrix): boolean {
        if (this.mMapMatrixS[JSON.stringify(matrix)]) {
            return true;
        }
        this.mMapMatrixS[JSON.stringify(matrix)] ="1";
        return false;
    }
}